//
// Created by wchenbt on 4/4/2021.
//
#ifdef ENABLE_MAPLE_SAN

#include "asan_config.h"
#include "asan_module.h"

#include "asan_interfaces.h"
#include "mir_builder.h"
#include <filesystem>

namespace maple {

std::string ModuleAddressSanitizer::GetSrcFilePath() const {
  char* filename = std::getenv(ASAN_MODULE_NAME_MACRO);
  if (filename == nullptr) {
    return module->GetFileNameWithPath();
  } else {
    std::filesystem::path _name = filename;
    if (_name.is_absolute()) {
      CHECK_FATAL(std::filesystem::exists(_name), "File not found: %s", _name.string().c_str());
      return _name.string();
    } else {
      std::filesystem::path ret = std::filesystem::current_path() / _name;
      CHECK_FATAL(std::filesystem::exists(ret), "File not found: %s", ret.string().c_str());
      return ret.string();
    }
  }
}

std::string ModuleAddressSanitizer::GetModuleSymbolPostfix() const {
  std::string ret = GetSrcFilePath();
  std::replace(ret.begin(), ret.end(), '/', '_');
  std::replace(ret.begin(), ret.end(), '.', '_');
  std::replace(ret.begin(), ret.end(), '-', '_');
  std::replace(ret.begin(), ret.end(), '@', '_');
  return ret;
}

MIRSymbol* ModuleAddressSanitizer::GetSymbolFromName(std::string name) {
  GStrIdx symIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(name);
  return GlobalTables::GetGlobalTables().GetGsymTable().GetSymbolFromStrIdx(symIdx);
}

void ModuleAddressSanitizer::AddGlobalChar(std::string name, char value, bool isInit) {
  MIRType *type = GlobalTables::GetTypeTable().GetPrimType(PTY_i8);
  MIRSymbol *symbol = nullptr;
  if (isInit) {
    symbol = module->GetMIRBuilder()->CreateSymbol(type->GetTypeIndex(), name, kStVar, kScGlobal, nullptr, kScopeGlobal);
  } else {
    symbol = GetSymbolFromName(name);
  }
  MIRConst *constValue = GlobalTables::GetIntConstTable().GetOrCreateIntConst(value, *type);
  symbol->SetKonst(constValue);
  if (isInit) {
    module->AddSymbol(symbol);
  }
}

void ModuleAddressSanitizer::AddGlobalInt(std::string name, int64_t value, bool isInit) {
  MIRType *type = GlobalTables::GetTypeTable().GetPrimType(PTY_i64);
  MIRSymbol *symbol = nullptr;
  if (isInit) {
    symbol = module->GetMIRBuilder()->CreateSymbol(type->GetTypeIndex(), name, kStVar, kScGlobal, nullptr, kScopeGlobal);
  } else {
    symbol = GetSymbolFromName(name);
  }
  MIRConst *constValue = GlobalTables::GetIntConstTable().GetOrCreateIntConst(value, *type);
  symbol->SetKonst(constValue);
  if (isInit) {
    module->AddSymbol(symbol);
  }
}

void ModuleAddressSanitizer::AddGlobalUInt(std::string name, uint64_t value, bool isInit) {
  MIRType *type = GlobalTables::GetTypeTable().GetPrimType(PTY_u64);
  MIRSymbol *symbol = nullptr;
  if (isInit) {
    symbol =  module->GetMIRBuilder()->CreateSymbol(type->GetTypeIndex(), name, kStVar, kScGlobal, nullptr, kScopeGlobal);
  } else {
    symbol = GetSymbolFromName(name);
  }
  MIRConst *constValue = GlobalTables::GetIntConstTable().GetOrCreateIntConst(value, *type);
  symbol->SetKonst(constValue);
  if (isInit) {
    module->AddSymbol(symbol);
  }
}

void ModuleAddressSanitizer::AddGlobalString(std::string name, std::string value, bool isInit) {
  MIRType *type =
      GlobalTables::GetTypeTable().GetOrCreatePointerType(*GlobalTables::GetTypeTable().GetPrimType(PTY_i8));
  MIRSymbol *symbol = nullptr;
  if (isInit) {
    symbol = module->GetMIRBuilder()->CreateSymbol(type->GetTypeIndex(), name, kStVar, kScGlobal, nullptr, kScopeGlobal);
  } else {
    symbol = GetSymbolFromName(name);
  }
  MIRStrConst *constValue = module->GetMemPool()->New<MIRStrConst>(value, *type);
  symbol->SetKonst(constValue);
  if (isInit) {
    module->AddSymbol(symbol);
  }
}

void ModuleAddressSanitizer::AddGlobalUIntArray(std::string name, std::vector<uint64_t> values, bool isInit) {
  MIRArrayType *arrayType =
      GlobalTables::GetTypeTable().GetOrCreateArrayType(*GlobalTables::GetTypeTable().GetUInt64(), 0);
  MIRSymbol * array = nullptr;
  if (isInit) {
    array = module->GetMIRBuilder()->CreateSymbol(arrayType->GetTypeIndex(), name, kStVar, kScGlobal, nullptr, kScopeGlobal);
  } else {
    array = GetSymbolFromName(name);
  }
  MIRAggConst *constArray = module->GetMemPool()->New<MIRAggConst>(*module, *arrayType);
  for (auto v : values) {
    constArray->PushBack(
        GlobalTables::GetIntConstTable().GetOrCreateIntConst(v, *GlobalTables::GetTypeTable().GetUInt64()));
  }
  array->SetKonst(constArray);
  if (isInit) {
    module->AddSymbol(array);
  }
}

void ModuleAddressSanitizer::AddSymbol(MIRSymbol* sym) {
  module->AddSymbol(sym);
}

void ModuleAddressSanitizer::initializeCallbacks() {
  MIRBuilder *mirBuilder = module->GetMIRBuilder();

  ArgVector args(module->GetMPAllocator().Adapter());
  MIRFunction *init_func =
      mirBuilder->CreateFunction(kAsanInitializer, *GlobalTables::GetTypeTable().GetVoid(), args, false, true);
  MIRFunction *fini_func =
      mirBuilder->CreateFunction(kAsanFinisher, *GlobalTables::GetTypeTable().GetVoid(), args, false, true);
  init_func->SetAttr(FUNCATTR_local);
  fini_func->SetAttr(FUNCATTR_local);

  module->AddFunction(init_func);
  module->AddFunction(fini_func);
  MIRType *retType = GlobalTables::GetTypeTable().GetVoid();

  // Declare functions that register/unregister globals.
  AsanRegisterGlobals = getOrInsertFunction(mirBuilder, kAsanRegisterGlobalsName, retType, {IntPtrTy, IntPtrTy});
  AsanUnregisterGlobals = getOrInsertFunction(mirBuilder, kAsanUnregisterGlobalsName, retType, {IntPtrTy, IntPtrTy});
}

MIRFunction* ModuleAddressSanitizer::GetGlobalCtor() const {
  MIRBuilder* mirBuilder = module->GetMIRBuilder();
  MIRFunction *ctor = mirBuilder->GetOrCreateFunction(kAsanInitializer, TyIdx(PTY_void));
  return ctor;
}

MIRFunction* ModuleAddressSanitizer::GetGlobalDtor() const {
  MIRBuilder* mirBuilder = module->GetMIRBuilder();
  MIRFunction *dtor = mirBuilder->GetOrCreateFunction(kAsanFinisher, TyIdx(PTY_void));
  return dtor;
}

void ModuleAddressSanitizer::AppendStmtToGlobalInit(StmtNode *node) {
  MIRFunction *GlobalCtors = GetGlobalCtor();
  GlobalCtors->GetBody()->AddStatement(node);
}

MIRFunction *ModuleAddressSanitizer::GetOrInsertFunction(const char *name, MIRType *retType, std::vector<MIRType *> argTypes) {
  MIRBuilder *mirBuilder = module->GetMIRBuilder();
  return getOrInsertFunction(mirBuilder, name, retType, argTypes);
}

bool ModuleAddressSanitizer::instrumentModule() {
  initializeCallbacks();
  MapleVector<BaseNode *> args(module->GetMIRBuilder()->GetCurrentFuncCodeMpAllocator()->Adapter());

  MIRBuilder *mirBuilder = module->GetMIRBuilder();
  MIRFunction *__asan_init =
      this->GetOrInsertFunction(kAsanInitName, GlobalTables::GetTypeTable().GetVoid(), {});
  MapleVector<BaseNode *> args__asan_init(mirBuilder->GetCurrentFuncCodeMpAllocator()->Adapter());
  // change current function of the builder since the call statement will be inserted into the __asan_init
  auto old_func = mirBuilder->GetCurrentFunction();
  mirBuilder->SetCurrentFunction(*__asan_init);
  CallNode *call__asan_init = mirBuilder->CreateStmtCall(__asan_init->GetPuidx(), args__asan_init);
  // reset !!!!!
  mirBuilder->SetCurrentFunction(*old_func);
  this->AppendStmtToGlobalInit(call__asan_init);
  // BlockNode *ctorToBeInserted = CreateCtorAndInitFunctions(kAsanModuleCtorName, kAsanInitName, args);

  // InstrumentGlobals(ctorToBeInserted);

  // appendToGlobalCtors(*module, AsanCtorFunction);
  if (AsanDtorFunction) {
    appendToGlobalDtors(*module, AsanDtorFunction);
  }
  module->SetSomeSymbolNeedForDecl(false);
  return true;
}

bool ModuleAddressSanitizer::InstrumentGlobals(BlockNode *ctorToBeInserted) {
  return false;
  std::vector<MIRSymbol *> globalsToChange;
  for (MIRSymbol *global : GetGlobalVaribles(*module)) {
    if (ShouldInstrumentGlobal(global)) {
      globalsToChange.push_back(global);
    }
  }

  size_t n = globalsToChange.size();
  if (n == 0) {
    return false;
  }
  FieldVector fieldVector;
  FieldVector parentFileds;
  std::vector<MIRSymbol *> newGlobals(n);
  std::vector<MIRConst *> initializers(n);

  // We initialize an array of such structures and pass it to a run-time call.
  GlobalTables::GetTypeTable().PushIntoFieldVector(fieldVector, "beg", *IntPtrTy);
  GlobalTables::GetTypeTable().PushIntoFieldVector(fieldVector, "size", *IntPtrTy);
  GlobalTables::GetTypeTable().PushIntoFieldVector(fieldVector, "size_with_redzone", *IntPtrTy);
  GlobalTables::GetTypeTable().PushIntoFieldVector(fieldVector, "name", *IntPtrTy);
  GlobalTables::GetTypeTable().PushIntoFieldVector(fieldVector, "module_name", *IntPtrTy);
  GlobalTables::GetTypeTable().PushIntoFieldVector(fieldVector, "has_dynamic_init", *IntPtrTy);
  GlobalTables::GetTypeTable().PushIntoFieldVector(fieldVector, "source_location", *IntPtrTy);
  GlobalTables::GetTypeTable().PushIntoFieldVector(fieldVector, "odr_indicator", *IntPtrTy);
  // Create new type for global with redzones
  MIRStructType *globalStructForInitTy = static_cast<MIRStructType *>(
      GlobalTables::GetTypeTable().GetOrCreateStructType("GlobalStruct", fieldVector, parentFileds, *module));

  for (size_t i = 0; i < n; i++) {
    static const uint64_t kMaxGlobalRedzone = 1 << 18;
    MIRSymbol *global = globalsToChange[i];
    // Compute the size of redzone
    size_t sizeInBytes = global->GetType()->GetSize();
    size_t minRedZone = MinRedzoneSizeForGlobal();
    size_t redzone = std::max(minRedZone, std::min(kMaxGlobalRedzone, ((sizeInBytes / minRedZone) / 4) * minRedZone));
    size_t rightRedzoneSize = redzone;
    if (sizeInBytes % minRedZone) {
      rightRedzoneSize += minRedZone - (sizeInBytes % minRedZone);
    }
    ASSERT(((rightRedzoneSize + sizeInBytes) % minRedZone) == 0,
           "rightRedzoneSize + sizeInBytes cannot be divided by minRedZone");

    // Create new type for global with redzones
    fieldVector.clear();
    parentFileds.clear();
    CHECK_FATAL(rightRedzoneSize < UINT32_MAX, "Too large redzone size.");
    MIRArrayType *rightRedZoneTy = GlobalTables::GetTypeTable().GetOrCreateArrayType(
        *GlobalTables::GetTypeTable().GetInt8(), uint32_t(rightRedzoneSize));
    GlobalTables::GetTypeTable().PushIntoFieldVector(fieldVector, "orig", *global->GetType());
    GlobalTables::GetTypeTable().PushIntoFieldVector(fieldVector, "redzone", *rightRedZoneTy);
    MIRStructType *newGlobalType = static_cast<MIRStructType *>(GlobalTables::GetTypeTable().GetOrCreateStructType(
        "NewGlobal_" + global->GetName(), fieldVector, parentFileds, *module));

    // Create new variable for global with redzones
    MIRSymbol *newGlobalVar = module->GetMIRBuilder()->CreateSymbol(
        newGlobalType->GetTypeIndex(), "", global->GetSKind(), global->GetStorageClass(), nullptr, kScopeGlobal);

    // Initialize the new global
    MIRAggConst *newGlobalConst = module->GetMemPool()->New<MIRAggConst>(*module, *newGlobalVar->GetType());
    // Initialize the field orig
    MIRConst *globalConst = global->GetKonst();
    MIRConst *globalConstClone;
    if (globalConst->GetKind() == kConstInt) {
      globalConstClone = GlobalTables::GetIntConstTable().GetOrCreateIntConst(
          static_cast<MIRIntConst *>(globalConst)->GetValue(), globalConst->GetType());
    } else {
      globalConstClone = globalConst->Clone(*module->GetMemPool());
    }
    newGlobalConst->AddItem(globalConstClone, 1);
    // Initialize the field redzone
    MIRAggConst *arrayConst = module->GetMemPool()->New<MIRAggConst>(*module, *rightRedZoneTy);
    for (size_t j = 0; j < rightRedzoneSize; j++) {
      arrayConst->AddItem(
          GlobalTables::GetIntConstTable().GetOrCreateIntConst(0, *GlobalTables::GetTypeTable().GetInt8()), 0);
    }

    newGlobalConst->AddItem(arrayConst, 2);
    // Set the initialized value to
    newGlobalVar->SetKonst(newGlobalConst);
    // Make the new created one the same as the old global variable
    newGlobalVar->SetAttrs(global->GetAttrs());
    newGlobalVar->SetNameStrIdx(global->GetName());
    // Set source location
    newGlobalVar->SetSrcPosition(global->GetSrcPosition());

    // replace global variable field Id
    for (MIRSymbol *mirSymbol : symbolUsedInInit[newGlobalVar->GetName()]) {
      MIRAddrofConst *mirAddrofConst = dynamic_cast<MIRAddrofConst *>(mirSymbol->GetKonst());
      MIRAddrofConst *newAddrofConst =
          module->GetMemPool()->New<MIRAddrofConst>(mirAddrofConst->GetSymbolIndex(), 1, mirAddrofConst->GetType());
      mirSymbol->SetKonst(newAddrofConst);
    }
    // replace statement field Id
    for (BaseNode *stmtNode : symbolUsedInStmt[newGlobalVar->GetName()]) {
      switch (stmtNode->GetOpCode()) {
        case OP_dassign: {
          DassignNode *dassignNode = dynamic_cast<DassignNode *>(stmtNode);
          dassignNode->SetStIdx(newGlobalVar->GetStIdx());
          dassignNode->SetFieldID(1 + dassignNode->GetFieldID());
          break;
        }
        case OP_dread:
        case OP_addrof: {
          AddrofNode *addrofNode = dynamic_cast<AddrofNode *>(stmtNode);
          addrofNode->SetStIdx(newGlobalVar->GetStIdx());
          addrofNode->SetFieldID(1 + addrofNode->GetFieldID());
          break;
        }
        case OP_callassigned: {
          CallNode *callNode = dynamic_cast<CallNode *>(stmtNode);
          CallReturnVector &callRet = callNode->GetReturnVec();
          for (size_t j = 0; j < callRet.size(); j++) {
            StIdx idx = callRet[j].first;
            RegFieldPair regFieldPair = callRet[j].second;
            if (!regFieldPair.IsReg()) {
              if (idx == global->GetStIdx()) {
                callRet[j].first = newGlobalVar->GetStIdx();
                callRet[j].second.SetFieldID(1 + callRet[j].second.GetFieldID());
              }
            }
          }
          break;
        }
        default: {
        }
      }
    }
    global->SetIsDeleted();
    newGlobalVar->ResetIsDeleted();
    // Create a new variable and construct its initial value
    MIRAggConst *initializer = module->GetMemPool()->New<MIRAggConst>(*module, *globalStructForInitTy);

    // begin
    MIRAddrofConst *beginConst = createAddrofConst(*module, newGlobalVar, IntPtrPrim);
    initializer->AddItem(beginConst, 1);
    // size
    MIRIntConst *sizeInBytesConst = GlobalTables::GetIntConstTable().GetOrCreateIntConst(sizeInBytes, *IntPtrTy);
    initializer->AddItem(sizeInBytesConst, 2);
    // size with redzone
    MIRIntConst *sizeWithRedzoneConst =
        GlobalTables::GetIntConstTable().GetOrCreateIntConst(sizeInBytes + rightRedzoneSize, *IntPtrTy);
    initializer->AddItem(sizeWithRedzoneConst, 3);
    // variable name
    MIRStrConst *nameConst = createStringConst(*module, newGlobalVar->GetName(), PTY_a64);
    initializer->AddItem(nameConst, 4);
    // module name
    MIRStrConst *moduleNameConst = createStringConst(*module, module->GetFileName(), PTY_a64);
    initializer->AddItem(moduleNameConst, 5);
    // isDynInit
    MIRIntConst *isDynInit = GlobalTables::GetIntConstTable().GetOrCreateIntConst(0, *IntPtrTy);
    initializer->AddItem(isDynInit, 6);
    // Set source location
    MIRConst *sourceLocConst = createSourceLocConst(*module, newGlobalVar, IntPtrPrim);
    initializer->AddItem(sourceLocConst, 7);
    // Set OdrIndicator
    MIRConst *odrIndicator = GlobalTables::GetIntConstTable().GetOrCreateIntConst(0, *IntPtrTy);
    initializer->AddItem(odrIndicator, 8);
    // Set the value of initializer
    LogInfo::MapleLogger() << "NEW GLOBAL: " << newGlobalVar->GetName() << "\n";
    newGlobals[i] = newGlobalVar;
    initializers[i] = initializer;
  }
  InstrumentGlobalsWithMetadataArray(ctorToBeInserted, newGlobals, initializers);
  return false;
}

bool ModuleAddressSanitizer::ShouldInstrumentGlobal(MIRSymbol *var) {
  MIRType *type = GlobalTables::GetTypeTable().GetTypeFromTyIdx(var->GetTyIdx());
  if (type == nullptr) {
    return false;
  }
  if (!isTypeSized(type)) {
    return false;
  }
  if (var->GetValue().konst == nullptr) {
    return false;
  }
  if (type->GetAlign() > MinRedzoneSizeForGlobal()) {
    return false;
  }
  return true;
}

void ModuleAddressSanitizer::InstrumentGlobalsWithMetadataArray(BlockNode *ctorToBeInserted,
                                                                const std::vector<MIRSymbol *> ExtendedGlobals,
                                                                std::vector<MIRConst *> MetadataInitializers) {
  assert(ExtendedGlobals.size() == MetadataInitializers.size());
  size_t N = ExtendedGlobals.size();
  CHECK_FATAL(N > 0, "Zero size extended globals.");
  MIRArrayType *arrayOfGlobalStructTy =
      GlobalTables::GetTypeTable().GetOrCreateArrayType(MetadataInitializers[0]->GetType(), N);
  MIRAggConst *allGlobalsConst = module->GetMemPool()->New<MIRAggConst>(*module, *arrayOfGlobalStructTy);
  for (MIRConst *meta : MetadataInitializers) {
    allGlobalsConst->PushBack(meta);
  }

  MIRSymbol *allGlobalsVar = module->GetMIRBuilder()->CreateSymbol(arrayOfGlobalStructTy->GetTypeIndex(), "allGlobals",
                                                                   kStConst, kScFstatic, nullptr, kScopeGlobal);
  allGlobalsVar->SetKonst(allGlobalsConst);
  MapleVector<BaseNode *> registerGlobal(module->GetMPAllocator().Adapter());
  AddrofNode *addrofNode = module->GetMIRBuilder()->CreateAddrof(*allGlobalsVar, IntPtrPrim);
  ConstvalNode *constvalNode = module->GetMIRBuilder()->CreateIntConst(N, IntPtrPrim);
  registerGlobal.emplace_back(addrofNode);
  registerGlobal.emplace_back(constvalNode);
  CallNode *registerCallNode = module->GetMIRBuilder()->CreateStmtCall(AsanRegisterGlobals->GetPuidx(), registerGlobal);
  ctorToBeInserted->InsertBefore(ctorToBeInserted->GetLast(), registerCallNode);
  BlockNode *dtorTobeInserted = CreateModuleDtor();
  // We also need to unregister globals at the end, e.g., when a shared library
  // gets closed.
  CallNode *unRegisterCallNode =
      module->GetMIRBuilder()->CreateStmtCall(AsanUnregisterGlobals->GetPuidx(), registerGlobal);
  dtorTobeInserted->InsertBefore(dtorTobeInserted->GetLast(), unRegisterCallNode);
}

BlockNode *ModuleAddressSanitizer::CreateCtorAndInitFunctions(const std::string CtorName, const std::string InitName,
                                                              const MapleVector<BaseNode *> InitArgs) {
  MIRBuilder *mirBuilder = module->GetMIRBuilder();
  ArgVector args(module->GetMPAllocator().Adapter());
  AsanCtorFunction = mirBuilder->CreateFunction(CtorName, *GlobalTables::GetTypeTable().GetVoid(), args);
  module->AddFunction(AsanCtorFunction);
  AsanCtorFunction->SetAttr(FUNCATTR_local);
  BlockNode *asanCtorBlock = AsanCtorFunction->GetBody();
  StmtNode *retNode = mirBuilder->CreateStmtReturn(nullptr);
  asanCtorBlock->AddStatement(retNode);

  MIRFunction *initFunction =
      getOrInsertFunction(mirBuilder, InitName.c_str(), GlobalTables::GetTypeTable().GetVoid(), {});
  CallNode *callInitNode = mirBuilder->CreateStmtCall(initFunction->GetPuidx(), InitArgs);

  asanCtorBlock->InsertBefore(retNode, callInitNode);
  return asanCtorBlock;
}

BlockNode *ModuleAddressSanitizer::CreateModuleDtor() {
  MIRBuilder *mirBuilder = module->GetMIRBuilder();
  ArgVector args(module->GetMPAllocator().Adapter());
  AsanDtorFunction = mirBuilder->CreateFunction(kAsanModuleDtorName, *GlobalTables::GetTypeTable().GetVoid(), args);
  module->AddFunction(AsanDtorFunction);
  AsanDtorFunction->SetAttr(FUNCATTR_local);
  BlockNode *asanDtorBlock = AsanDtorFunction->GetBody();
  StmtNode *retNode = mirBuilder->CreateStmtReturn(nullptr);
  asanDtorBlock->AddStatement(retNode);

  return asanDtorBlock;
}

void ModuleAddressSanitizer::GetGlobalSymbolUsage() {
  // Replace all old global users with new global
  for (MIRFunction *func : module->GetFunctionList()) {
    if (func == nullptr || func->GetBody() == nullptr) {
      continue;
    }
    std::stack<BaseNode *> baseNodeStack;
    StmtNodes &stmtNodes = func->GetBody()->GetStmtNodes();
    for (StmtNode &stmt : stmtNodes) {
      baseNodeStack.push(&stmt);
    }

    while (!baseNodeStack.empty()) {
      BaseNode *baseNode = baseNodeStack.top();
      baseNodeStack.pop();
      switch (baseNode->GetOpCode()) {
        case OP_dassign: {
          DassignNode *dassignNode = dynamic_cast<DassignNode *>(baseNode);
          MIRSymbol *mirSymbol = func->GetLocalOrGlobalSymbol(dassignNode->GetStIdx());
          if (mirSymbol->IsGlobal()) {
            if (symbolUsedInStmt.count(mirSymbol->GetName()) == 0) {
              symbolUsedInStmt[mirSymbol->GetName()] = {};
            }
            symbolUsedInStmt[mirSymbol->GetName()].insert(dassignNode);
          }
          break;
        }
        case OP_dread:
        case OP_addrof: {
          AddrofNode *addrofNode = dynamic_cast<AddrofNode *>(baseNode);
          MIRSymbol *mirSymbol = func->GetLocalOrGlobalSymbol(addrofNode->GetStIdx());
          if (mirSymbol->IsGlobal()) {
            if (symbolUsedInStmt.count(mirSymbol->GetName()) == 0) {
              symbolUsedInStmt[mirSymbol->GetName()] = {};
            }
            symbolUsedInStmt[mirSymbol->GetName()].insert(addrofNode);
          }
          break;
        }
        case OP_callassigned: {
          CallNode *callNode = dynamic_cast<CallNode *>(baseNode);
          CallReturnVector &callRet = callNode->GetReturnVec();
          for (size_t i = 0; i < callRet.size(); i++) {
            StIdx idx = callRet[i].first;
            RegFieldPair regFieldPair = callRet[i].second;
            if (!regFieldPair.IsReg()) {
              MIRSymbol *mirSymbol = func->GetLocalOrGlobalSymbol(idx);
              if (mirSymbol->IsGlobal()) {
                if (symbolUsedInStmt.count(mirSymbol->GetName()) == 0) {
                  symbolUsedInStmt[mirSymbol->GetName()] = {};
                }
                symbolUsedInStmt[mirSymbol->GetName()].insert(callNode);
              }
            }
          }
          break;
        }
        default:
          break;
      }
      for (size_t j = 0; j < baseNode->NumOpnds(); j++) {
        baseNodeStack.push(baseNode->Opnd(j));
      }
    }
  }
  for (MIRSymbol *mirSymbol : GetGlobalVaribles(*module)) {
    if (mirSymbol->GetKonst()) {
      MIRConst *mirConst = mirSymbol->GetKonst();
      if (mirConst->GetKind() == kConstAddrof) {
        MIRAddrofConst *mirAddrofConst = dynamic_cast<MIRAddrofConst *>(mirConst);
        MIRSymbol *mirSymbolUsed =
            GlobalTables::GetGsymTable().GetSymbolFromStidx(mirAddrofConst->GetSymbolIndex().Idx());
        if (symbolUsedInInit.count(mirSymbolUsed->GetName()) == 0) {
          symbolUsedInInit[mirSymbolUsed->GetName()] = {};
        }
        symbolUsedInInit[mirSymbolUsed->GetName()].insert(mirSymbol);
      }
    }
  }
}
}  // namespace maple

#endif